from ihome.settings import logger
from libs.qiniuyun.qiniu_storage import storage
from utils import constants
from django.conf import settings
from django.db import transaction
from apps.houses.models import Facility, HouseImage
from django.views import View
from django.http import JsonResponse
import json
from datetime import datetime
from apps.houses.models import Area, House
from apps.orders.models import Order
from django.core.paginator import Paginator
from ihome import settings
from django_redis import get_redis_connection


class HouseList(View):
    """
       我的房屋列表
    """

    def get(self, request):
        # 判断用户是否登录
        if not request.user.is_authenticated:
            # 未登录,返回前端
            return JsonResponse({"errno": 4101, 'errmsg': '用户未登录'}, status=400)
        else:
            # 获取用户
            user = request.user
            # 构造有序字典
            data_dict = {}
            # 获取当前用户所有房源信息
            H = HouseImage()
            houses = House.objects.filter(user_id=user.id)

            for house in houses:
                # 提取分组信息
                house_id = house.house_id
                # 判断house_id是否已经在字典中存在
                if house_id not in data_dict:
                    # 使用'data'作为data_dict的key,进行赋值
                    data_dict['data'] = {'houses': []}

                data_dict['data']['houses'].append({
                    "address": house.address,
                    "area_name": house.area.name,
                    "ctime": house.create_time,
                    "house_id": H.house_id,
                    "img_url": H.url,
                    "order_count": house.order_count,
                    "price": house.price,
                    "room_count": house.room_count,
                    "title": house.title,
                    "user_avatar": house.user.avatar

                })

            return JsonResponse({
                'data': data_dict,
                'errmsg': 'ok',
                'errno': 0})


class HouseIndex(View):
    """
       首页房屋推荐
    """

    def get(self, request):

        # 获取前端传递的分页数据和排序数据，查询字符串形式传递
        page = request.GET.get('p')  # 第几页的页数
        try:
            page = int(page)
        except:
            page = 1

        # 查询房屋信息 按照房屋订单号排序
        try:
            hh = HouseImage.objects.order_by('house_id')
        except:
            return JsonResponse({"errno": 4101}, status=400)
        # 对商品数据进行分页处理，使用Django的分页类的方法
        # 初始化分页类生成分页对象,需要传递两个参数，第一个要分页的数据，第二个分页后每页的数量
        paginator = Paginator(hh, 5)
        # 提取分页数据数据，将页数传递的进去，根据传递分页数据进行响应分页数据获取
        try:
            hhh = paginator.page(page)
        except:
            return JsonResponse({"errno": 4101}, status=400)
        # 构造有序字典
        data_list = []
        for h in hhh:
            data_list.append({
                "house_id": h.house_id,
                "img_url": settings.QINIU_URL+h.url,
                "title": h.house.title})
        return JsonResponse({
            'data': data_list,
            'errmsg': 'ok',
            'errno': 0})


class SearchHouseView(View):

    def get(self, request):

        # 获取数据
        start_date = request.GET.get("sd", '')  # 起始时间
        end_date = request.GET.get("ed", '')  # 结束时间
        area_id = request.GET.get("aid", '')  # 区域编号
        sort_key = request.GET.get("sk", 'new')  # 排序关键字
        page = request.GET.get("p")  # 页数
        # 处理页数

        try:
            page = int(page)
        except:
            page = 1

        # 查询房屋信息 按照房屋订单号排序
        try:
            hh = HouseImage.objects.order_by('house_id')
        except:
            return JsonResponse({"errno": 4101}, status=400)
        # 对商品数据进行分页处理，使用Django的分页类的方法
        # 初始化分页类生成分页对象,需要传递两个参数，第一个要分页的数据，第二个分页后每页的数量
        paginator = Paginator(hh, 5)
        # 提取分页数据数据，将页数传递的进去，根据传递分页数据进行响应分页数据获取
        try:
            hhh = paginator.page(page)
        except:
            return JsonResponse({"errno": 4101}, status=400)
        # 构造有序字典
        data_list = []
        for h in hhh:
            data_list.append({
                "house_id": h.house_id,
                "img_url": h.url,
                "title": h.house.title})
        return JsonResponse({
            'data': data_list,
            'errmsg': 'ok',
            'errno': 0})


class CityAreaView(View):
    """城区"""

    def get(self, request):
        """获取城区信息"""
        try:
            # 1.查询所有城区数据
            area_list = Area.objects.all()

            # 2.整理城区数据
            data = []
            for area in area_list:
                data.append({'aid': area.id, 'aname': area.name})

        except Exception as e:
            # 如果报错, 则返回错误原因:
            return JsonResponse({'errno': 4001, 'errmsg': '数据库查询错误'})

        # 3.响应获取到的城区信息
        return JsonResponse({'errno': 0, 'errmsg': '获取成功', 'data': data})


class HouseView(View):
    """房源"""

    def post(self, request):
        """发布房源"""

        # 获取前端传递的数据
        data_dict = json.loads(request.body.decode())
        title = data_dict.get('title')  # 标题
        price = data_dict.get('price')  # 房屋单价
        area_id = data_dict.get('area_id')  # 城区id
        address = data_dict.get('address')  # 房屋地址
        room_count = data_dict.get('room_count')  # 房间数目
        acreage = data_dict.get('acreage')  # 房屋面积
        unit = data_dict.get('unit')  # 房屋单元
        capacity = data_dict.get('capacity')  # 房屋容纳的人数
        beds = data_dict.get('beds')  # 房屋床铺的配置
        deposit = data_dict.get('deposit')  # 押金
        min_days = data_dict.get('min_days')  # 最少入住天数
        max_days = data_dict.get('max_days')  # 最大入住天数，0表示不限制
        facility_id_list = data_dict.get('facility')  # 用户选择的设施信息id列表，如：[7, 8]

        # 校验数据完整性
        if not all([title, price, area_id, address, room_count, acreage,
                    unit, capacity, beds, deposit, min_days, max_days, facility_id_list]):
            return JsonResponse({'errno': 4103, 'errmsg': '缺少必传参数'})

        # 校验标题
        if not title:
            return JsonResponse({'errno': 4103, 'errmsg': '参数错误'})

        # 校验房屋单价和押金是否位数字
        try:
            price = float(price)
            deposit = float(deposit)
        except Exception as e:
            logger.error(e)
            return JsonResponse({'errno': 4103, 'errmsg': '参数错误'})

        # 判断城区id是否存在
        try:
            area = Area.objects.get(area_id)
        except Exception as e:
            logger.error(e)
            return JsonResponse({'errno': 4103, 'errmsg': '参数错误'})

        # 校验房屋地址
        if not address:
            return JsonResponse({'errno': 4103, 'errmsg': '参数错误'})

        # 校验房间数目
        if not room_count:
            return JsonResponse({'errno': 4103, 'errmsg': '参数错误'})

        # 校验房屋面积
        if not acreage:
            return JsonResponse({'errno': 4103, 'errmsg': '参数错误'})

        # 校验房屋单元
        if not unit:
            return JsonResponse({'errno': 4103, 'errmsg': '参数错误'})

        # 校验房屋容纳人数
        if not capacity:
            return JsonResponse({'errno': 4103, 'errmsg': '参数错误'})

        # 校验房屋床铺配置
        if not beds:
            return JsonResponse({'errno': 4103, 'errmsg': '参数错误'})

        # 校验最少入住天数
        if not min_days:
            return JsonResponse({'errno': 4103, 'errmsg': '参数错误'})

        # 校验最大入住天数
        if not max_days:
            return JsonResponse({'errno': 4103, 'errmsg': '参数错误'})

        # 校验房屋设施信息
        try:
            facilities = Facility.objects.filter(id_in=facility_id_list).all()
        except Exception as e:
            logger.error(e)
            return JsonResponse({'errno': 4001, 'errmsg': '数据库查询错误'})

        # 用事物来保存房源信息
        with transaction.atomic():
            # 设置事物保存点
            save_id = transaction.savepoint()

            try:
                house = House.objects.create(
                    user=request.user,
                    title=title,
                    price=price,  # 房屋单价
                    area_id=area_id,  # 城区id
                    address=address,
                    room_count=room_count,
                    acreage=acreage,
                    unit=unit,
                    capacity=capacity,
                    beds=beds,
                    deposit=deposit,  # 押金
                    min_days=min_days,
                    max_days=max_days,
                    facility=facilities
                )

            except Exception as e:
                logger.error(e)
                # 事物回滚到保存点
                transaction.savepoint_rollback(save_id)
                return JsonResponse({'errno': 4004, 'errmsg': '保存房源信息失败'})
            # 事物提交
            transaction.savepoint_commit(save_id)
            # 构造响应数据

            data = {
                "house_id": house.id
            }

        # 响应结果
        return JsonResponse({'errno': 0, 'errmsg': '发布成功', 'data': data})


class HouseImageView(View):
    """房源图片"""

    def post(self, request, house_id):
        """上传房源图片"""

        # 获取前端传递的参数
        image_file = request.FILES.get('house_image')

        # 校验参数
        if not image_file:
            return JsonResponse({'errno': 4103, 'errmsg': '参数错误'})

        # 判断房源信息是否存在
        try:
            house = House.objects.get(id=house_id)
        except Exception as e:
            logger.error(e)
            return JsonResponse({"errno": 4002, "errmsg": "房源信息不存在"})

        # 保存房源图片到七牛
        image_data = image_file.read()
        try:
            image_name = storage(image_data)

        except Exception as e:
            logger.error(e)
            return JsonResponse({'errno': 4301, 'errmsg': '保存房源图片失败'})

        # 将七牛中的房源图片路径(image_name)保存到数据库中

        with transaction.atomic():
            # 事物保存点
            save_id = transaction.savepoint()
            try:
                # 房屋主图片路径为空，直接添加路径
                if not house.index_image_url:
                    house.index_image_url = image_name
                    house.save()
                # 房屋主图片路径不为空，更新路径
                else:
                    house_image = HouseImage()
                    house_image.house = house
                    house_image.url = image_name
                    house_image.save()
            except Exception as e:
                logger.error(e)
                # 事物回滚到保存点
                transaction.savepoint_rollback(save_id)
            # 事务提交
            transaction.savepoint_commit(save_id)

        # 构造响应数据

        data = {
            "url": "http://qexn0ws50.hn-bkt.clouddn.com" + image_name
        }

        # 响应结果

        return JsonResponse({'errno': 0, 'errmsg': '图片上传成功', 'data': data})

        redis_conn = get_redis_connection("house_cache")
        try:
            redis_key = "houses_%s_%s_%s_%s" % (area_id, start_date, end_date, sort_key)
            data = redis_conn.hget(redis_key, page)
            if data:
                data1 = json.loads(data)
                return JsonResponse({"errno": '0', "errmsg": "OK", "data": data1})
        except:
            return JsonResponse({"errno": '4001', "errmsg": "数据库错误"})
        # 判断选定的时间对错
        try:
            if start_date:
                start_date = datetime.strptime(start_date, "%Y-%m-%d")

            if end_date:
                end_date = datetime.strptime(end_date, "%Y-%m-%d")
            # 如果开始时间大于或者等于结束时间,就报错
            if start_date and end_date:
                raise start_date <= end_date
        except:
            return JsonResponse({"errno": '4103', "errmsg": "选定日期不正确"}, status=400)

        # 过滤条件的列表容器
        filter_params = {}

        # 5.判断前端的区域id是否在数据库中存在
        if area_id:
            filter_params[area_id] = area_id

        # 填充过滤条件

        if start_date and end_date:
            # 查询冲突的订单
            conflict_orders = Order.objects.filter(
                Order.begin_date <= end_date, Order.end_date >= start_date).all()

        elif start_date:
            # 查询冲突的订单
            conflict_orders = Order.objects.filter(Order.end_date >= start_date).all()
        elif end_date:
            # 查询冲突的订单
            conflict_orders = Order.objects.filter(Order.begin_date <= end_date).all()
        else:
            conflict_orders = []

        # 从订单中获取冲突的房子 id
        conflict_house_ids = [order.house_id for order in conflict_orders]

        # 如果冲突的房子id不为空，向查询的参数中添加条件
        if conflict_house_ids:
            filter_params["id__in"] = conflict_house_ids

        # 查询数据库, 加过滤排序条件
        if sort_key == 'booking':
            house_query = House.objects.filter(**filter_params).order_by('-order_count')
        elif sort_key == 'price-inc':
            house_query = House.objects.filter(**filter_params).order_by('price')
        elif sort_key == 'price-des':
            house_query = House.objects.filter(**filter_params).order_by('-price')
        else:
            house_query = House.objects.filter(**filter_params).order_by('-create_time')  # 新旧

        # 分页处理
        paginator = Paginator(house_query, constants.HOUSE_LIST_PAGE_CAPACITY)
        try:
            page_houses = paginator.page(page)
        except:
            return JsonResponse({'errno': '4003'}, status=400)

        # 获取总页数
        total_page = paginator.num_pages

        # 4、构造返回结果
        houses = []
        for page_house in page_houses:
            houses.append({
                "house_id": page_house.id,
                "title": page_house.title,
                "price": page_house.price,
                "area_name": page_house.area.name,
                "img_url": settings.QINIU_URL + page_house.index_image_url if page_house.index_image_url else "",
                "room_count": page_house.room_count,
                "order_count": page_house.order_count,
                "address": page_house.address,
                "user_avatar": settings.QINIU_URL + page_house.user.avatar.name if page_house.user.avatar.name else "",
                "ctime": page_house.create_time.strftime("%Y-%m-%d")
            })

        data = {
                   'house': houses,
                   "total_page": total_page,
               },
        if page <= total_page:
            try:
                # 生成缓存用的key
                redis_key = "houses_%s_%s_%s_%s" % (area_id, start_date, end_date, sort_key)
                # 获取 redis_store 的 pipeline 对象,其可以一次可以做多个redis操作
                pl = redis_conn.pipeline()
                # 开启事务
                pl.multi()
                # 缓存数据
                pl.hset(redis_key, page, json.dumps(data))
                # 设置保存数据的有效期
                pl.expire(redis_key, constants.HOUSE_LIST_REDIS_EXPIRES)
                # 提交事务
                pl.execute()
            except:
                return JsonResponse({"errno": '4001', "errmsg": "保存失败"})

        return JsonResponse({
            "data": data,
            "errmsg": "请求成功",
            "errno": "0",

        })


class HouseDetailsView(View):
    """
        房屋详情页
        """

    def get(self, request, house_id):

        try:
            house = House.objects.get(id=house_id)
        except:

            return JsonResponse({"errno": '4001', "errmsg": "数据错误"})

        user = request.user
        # is_authenticated验证是否登陆
        if not user.is_authenticated:
            user_id = -1
        else:
            user_id = user.id
        # 先从redis缓存中取
        redis_conn = get_redis_connection("house_cache")

        house_dicts = redis_conn.get('house_info_%d' % house_id)

        # 如果有值,那么返回数据
        if house_dicts:
            house_dict = json.loads(house_dicts)
            return JsonResponse(
                {"errno": '0', "errmsg": "OK", "data": {"user_id": user_id, "house": house_dict}})

        # 将数据缓存到redis中
        # house_dict = house.to_full_dict()
        house_dict = {
            "hid": house.id,
            "user_id": user.id,
            "user_name": user.username,
            "user_avatar": settings.QINIU_URL + house.user.avatar.name if house.user.avatar.name else "",
            "title": house.title,
            "price": house.price,
            "address": house.address,
            "room_count": house.room_count,
            "acreage": house.acreage,
            "unit": house.unit,
            "capacity": house.capacity,
            "beds": house.beds,
            "deposit": house.deposit,
            "min_days": house.min_days,
            "max_days": house.max_days,
        }
        # 房屋图片
        img_urls = []
        for image in house.houseimage_set.all():
            img_urls.append(settings.QINIU_URL + image.url)
        house_dict["img_urls"] = img_urls

        # 房屋设施
        facilities = []
        for facility in house.facility.all():
            facilities.append(facility.id)
        house_dict["facilities"] = facilities

        # 评论信息
        comments = []
        orders = Order.objects.filter(house=house, status=Order.ORDER_STATUS["COMPLETE"],
                                      comment__isnull=False).order_by("-update_time")[0:30]
        for order in orders:
            comment = {
                "comment": order.comment,  # 评论的内容
                "user_name": order.user.username if order.user.username != order.user.mobile else "匿名用户",  # 发表评论的用户
                "ctime": order.update_time.strftime("%Y-%m-%d %H:%M:%S")  # 评价的时间
            }
            comments.append(comment)
        house_dict["comments"] = comments

        try:
            redis_conn.setex('house_info_%d' % house_id, constants.HOUSE_DETAIL_REDIS_EXPIRE_SECOND,
                             json.dumps(house_dict))
        except:
            return JsonResponse({"errno": '400', "errmsg": "失败"})
        # 返回数据
        return JsonResponse({"errno": '0', "errmsg": "OK", "data": {"user_id": user_id, "house": house_dict}})
